package com.sxf.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Preconditions;
import org.apache.commons.configuration.plist.XMLPropertyListConfiguration.ArrayNode;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.List;


/**
 * @author guolei
 * @title: JacksonUtils
 * @projectName ccccit-lego
 * @description: TODO
 * @date 2020-08-1910:01
 */
public class JacksonUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(JacksonUtils.class);

    private static final String DATE_STRING = "yyyy-MM-dd HH:mm:ss";

    private static final ObjectMapper OBJECT_MAPPER;

    static {
        OBJECT_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .setSerializationInclusion(JsonInclude.Include.NON_NULL)
                .setDateFormat(new SimpleDateFormat(DATE_STRING))
        .configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)
        .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
    }


    public static <T> T toObject(String text, Class<T> cls) {
        Preconditions.checkNotNull(text);
        Preconditions.checkArgument(StringUtils.isNotEmpty(text));

        try {
            return OBJECT_MAPPER.readValue(text, cls);
        } catch (IOException e) {
            LOGGER.error("JacksonUtil.fromJsonToObject(String text,Class<T> cls) is error", e);
        }

        return null;
    }

    public static <T> T toSpecificObject(Object object, Class<T> cls) {
        Preconditions.checkNotNull(object);

        return OBJECT_MAPPER.convertValue(object, cls);
    }

    public static <T> T toObject(String text, TypeReference<T> type) {
        Preconditions.checkNotNull(text);
        Preconditions.checkArgument(StringUtils.isNotEmpty(text));

        try {
            return OBJECT_MAPPER.readValue(text, type);
        } catch (IOException e) {
            LOGGER.error("JacksonUtil.fromJsonToObject(String text, TypeReference<T> type) is error", e);
        }

        return null;
    }
    
    public static <T> T toObject(byte[] dataByte, TypeReference<T> type) {
    	Preconditions.checkNotNull(dataByte);
    	try {
    		return OBJECT_MAPPER.readValue(dataByte, type);
    	} catch (IOException e) {
    		LOGGER.error("JacksonUtil.fromJsonToObject(String text, TypeReference<T> type) is error", e);
    	}
    	
    	return null;
    }
    
    public static <T> T toObject(byte[] dataByte, Class<T> cls) {
    	Preconditions.checkNotNull(dataByte);
    	if(dataByte.length == 0) {
    		return null;
    	}
    	try {
    		return OBJECT_MAPPER.readValue(dataByte, cls);
    	} catch (IOException e) {
    		LOGGER.error("JacksonUtil.fromJsonToObject(String text, TypeReference<T> type) is error", e);
    	}
    	
    	return null;
    }
    
    public static <T> T toObject(byte[] dataByte, JavaType javaType) {
    	Preconditions.checkNotNull(dataByte);
    	try {
    		return OBJECT_MAPPER.readValue(dataByte, javaType);
    	} catch (IOException e) {
    		LOGGER.error("JacksonUtil.fromJsonToObject(String text, TypeReference<T> type) is error", e);
    	}
    	
    	return null;
    }

    public static String toJsonString(Object obj) {
        Preconditions.checkNotNull(obj);

        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            LOGGER.error("JacksonUtil.fromObjectToJson(Object obj) is error", e);
        }
        return null;
    }

    public static ArrayNode toArrayNode(String text) {
        Preconditions.checkNotNull(text);
        Preconditions.checkArgument(StringUtils.isNotEmpty(text));

        try {
            return OBJECT_MAPPER.readValue(text, ArrayNode.class);
        } catch (IOException e) {
            LOGGER.error("JacksonUtil.fromJsonToArray is error", e);
        }
        return null;
    }

    public static ObjectNode toObjectNode(String text) {
        Preconditions.checkNotNull(text);
        Preconditions.checkArgument(StringUtils.isNotEmpty(text));

        try {
            return OBJECT_MAPPER.readValue(text, ObjectNode.class);
        } catch (IOException e) {
            LOGGER.error("JacksonUtil.fromJsonToObject(String text) is error", e);
        }
        return null;
    }

    public static ObjectNode toObjectNode(Object obj){
        Preconditions.checkNotNull(obj);
        try{
            String str = OBJECT_MAPPER.writeValueAsString(obj);
            return OBJECT_MAPPER.readValue(str, ObjectNode.class);
        } catch (IOException e){
            LOGGER.error("JacksonUtil.toObjectNode(String text) is error", e);
        }
        return null;
    }

    public static List<?> toArrayList(String text, Class<?> elementClasses) {
        Preconditions.checkNotNull(text);
        Preconditions.checkArgument(StringUtils.isNotEmpty(text));

        try {
            return OBJECT_MAPPER.readValue(text, getCollectionType(List.class, elementClasses));
        } catch (IOException e) {
            LOGGER.error("JacksonUtil.fromJsonToArray(String text,Class<?> collectionClass, Class<?>... elementClasses) is error", e);
        }
        return Collections.emptyList();
    }

    public static String getMemberValue(ObjectNode objectNode, String member) {
        Preconditions.checkNotNull(objectNode);

        try {
            if (!objectNode.has(member)) {
                return null;
            }
            return objectNode.get(member).asText();
        } catch (Exception e) {
            LOGGER.error("JacksonUtil.fromJsonToArray(String text,Class<?> collectionClass, Class<?>... elementClasses) is error", e);
        }

        return null;
    }

    private static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
        return OBJECT_MAPPER.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

}
